home *** CD-ROM | disk | FTP | other *** search
/ Giga Games 1 / Giga Games.iso / net / hack / 3_1_3 / sys / amiga / amiwind.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-04-30  |  27.8 KB  |  1,219 lines

  1. /*    SCCS Id: @(#)amiwind.c     3.1    93/01/08
  2. /*    Copyright (c) Olaf Seibert (KosmoSoft), 1989, 1992      */
  3. /*    Copyright (c) Kenneth Lorber, Bethesda, Maryland 1993      */
  4. /* NetHack may be freely redistributed.  See license for details. */
  5.  
  6. #include "amiga:windefs.h"
  7. #include "amiga:winext.h"
  8. #include "amiga:winproto.h"
  9.  
  10. /* Have to undef CLOSE as display.h and intuition.h both use it */
  11. #undef CLOSE
  12.  
  13. #ifdef AMII_GRAPHICS    /* too early in the file? too late? */
  14.  
  15. #ifndef    SHAREDLIB
  16. struct Library *ConsoleDevice;
  17. #endif
  18.  
  19. #include "Amiga:amimenu.c"
  20.  
  21. static int BufferGetchar(void);
  22. static void ProcessMessage( register struct IntuiMessage *message );
  23.  
  24. #ifdef AMIFLUSH
  25. static struct Message *FDECL(GetFMsg,(struct MsgPort *));
  26. #endif
  27.  
  28. /*  Now our own variables */
  29.  
  30. struct IntuitionBase *IntuitionBase;
  31. #ifndef    SHAREDLIB
  32. struct Screen *HackScreen;
  33. #endif
  34. struct Window *pr_WindowPtr;
  35. struct MsgPort *HackPort;
  36. struct IOStdReq ConsoleIO;
  37. #ifndef    SHAREDLIB
  38. char Initialized = 0;
  39. #endif
  40. WEVENT lastevent;
  41.  
  42. #ifdef HACKFONT
  43. struct GfxBase *GfxBase;
  44. struct Library *DiskfontBase;
  45. #endif
  46.  
  47. #ifndef    SHAREDLIB
  48. extern struct Library *ConsoleDevice;
  49. #endif
  50.  
  51. #define KBDBUFFER   10
  52. static unsigned char KbdBuffer[KBDBUFFER];
  53. unsigned char KbdBuffered;
  54.  
  55. #define BufferQueueChar(ch) (KbdBuffer[KbdBuffered++] = (ch))
  56.  
  57. /*
  58.  * Define some stuff for our special glyph drawing routines
  59.  */
  60. static unsigned short glyph_node_index, glyph_buffer_index;
  61. #define NUMBER_GLYPH_NODES  80
  62. #define GLYPH_BUFFER_SIZE   512
  63. struct glyph_node {
  64.     short    x;
  65.     short    y;
  66.     short    len;
  67.     unsigned char   bg_color;
  68.     unsigned char   fg_color;
  69.     char    *buffer;
  70. };
  71. static struct glyph_node g_nodes[NUMBER_GLYPH_NODES];
  72. static char glyph_buffer[GLYPH_BUFFER_SIZE];
  73.  
  74. #ifdef TEXTCOLOR
  75. /*
  76.  * Map our amiga-specific colormap into the colormap specified in color.h.
  77.  * See amiwind.c for the amiga specific colormap.
  78.  */
  79.  
  80. #ifdef    VIEWWINDOW
  81. int foreg[16] = { 8, 7, 4, 2, 6, 5, 3, 1, 1, 0, 0, 0, 0, 0, 0, 0 };
  82. int backg[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 4, 1, 6, 5, 3, 1 };
  83. #else
  84. int foreg[16] = { 0, 7, 4, 2, 6, 5, 3, 1, 1, 0, 0, 0, 0, 0, 0, 0 };
  85. int backg[16] = { 1, 0, 0, 0, 0, 0, 0, 0, 0, 7, 4, 1, 6, 5, 3, 1 };
  86. #endif
  87. #if 0
  88.     #define BLACK        0
  89.     #define RED        1
  90.     #define GREEN        2
  91.     #define BROWN        3    /* on IBM, low-intensity yellow is brown */
  92.     #define BLUE        4
  93.     #define MAGENTA     5
  94.     #define CYAN        6
  95.     #define GRAY        7    /* low-intensity white */
  96.     #define NO_COLOR    8
  97.     #define ORANGE_COLORED    9    /* "orange" conflicts with the object */
  98.     #define BRIGHT_GREEN    10
  99.     #define YELLOW        11
  100.     #define BRIGHT_BLUE    12
  101.     #define BRIGHT_MAGENTA  13
  102.     #define BRIGHT_CYAN    14
  103.     #define WHITE        15
  104.     #define MAXCOLORS    16
  105. #endif
  106. #endif
  107.  
  108. #ifdef HACKFONT
  109.  
  110. struct TextFont *TextsFont;
  111. struct TextFont *HackFont;
  112. #ifdef    VIEWWINDOW
  113. struct TextFont *HackFont4;
  114. struct TextFont *HackFont16;
  115. #endif
  116. UBYTE FontName[] = "NetHack:hack.font";
  117.     /* # chars in "NetHack:": */
  118. #define         SIZEOF_DISKNAME 8
  119.  
  120. #endif
  121.  
  122. struct TextAttr Hack80 = {
  123. #ifdef HACKFONT
  124.     &FontName[SIZEOF_DISKNAME],
  125. #else
  126.     (UBYTE *) "topaz.font",
  127. #endif
  128.     8, FS_NORMAL, FPF_DISKFONT | FPF_DESIGNED
  129.     | FPF_ROMFONT
  130. };
  131.  
  132. #ifdef    VIEWWINDOW
  133. struct TextAttr Hack40 = {
  134. #ifdef HACKFONT
  135.     &FontName[SIZEOF_DISKNAME],
  136. #else
  137.     (UBYTE *) "topaz.font",
  138. #endif
  139.     4, FS_NORMAL, FPF_DISKFONT | FPF_DESIGNED
  140. #ifndef    HACKFONT
  141.     | FPF_ROMFONT
  142. #endif
  143. };
  144.  
  145. struct TextAttr Hack160 = {
  146. #ifdef HACKFONT
  147.     &FontName[SIZEOF_DISKNAME],
  148. #else
  149.     (UBYTE *) "topaz.font",
  150. #endif
  151.     16, FS_NORMAL, FPF_DISKFONT | FPF_DESIGNED
  152. #ifndef    HACKFONT
  153.     | FPF_ROMFONT
  154. #endif
  155. };
  156. #endif
  157.  
  158. struct TextAttr TextsFont13 = {
  159.     (UBYTE *) "courier.font",
  160.     13, FS_NORMAL, FPF_DISKFONT | FPF_DESIGNED
  161. #ifndef    HACKFONT
  162.     | FPF_ROMFONT
  163. #endif
  164. };
  165.  
  166. /*
  167.  * Open a window that shares the HackPort IDCMP. Use CloseShWindow()
  168.  * to close.
  169.  */
  170.  
  171. struct Window *OpenShWindow(nw)
  172. struct NewWindow *nw;
  173. {
  174.     register struct Window *win;
  175.     register ULONG idcmpflags;
  176.  
  177.     if (!HackPort)  /* Sanity check */
  178.     return (struct Window *) 0;
  179.  
  180.     idcmpflags = nw->IDCMPFlags;
  181.     nw->IDCMPFlags = 0;
  182.     if (!(win = OpenWindow((void *)nw)))
  183.     return (struct Window *) 0;
  184.  
  185.     win->UserPort = HackPort;
  186.     ModifyIDCMP(win, idcmpflags);
  187.     return win;
  188. }
  189.  
  190.  
  191. /*
  192.  * Close a window that shared the HackPort IDCMP port.
  193.  */
  194.  
  195. void FDECL(CloseShWindow, (struct Window *));
  196. void CloseShWindow(win)
  197. struct Window *win;
  198. {
  199.     register struct IntuiMessage *msg;
  200.  
  201.     if( !HackPort )
  202.     panic("HackPort NULL in CloseShWindow" );
  203.     if (!win)
  204.     return;
  205.  
  206.     Forbid();
  207.     /* Flush all messages for all windows to avoid typeahead and other
  208.      * similar problems...
  209.      */
  210.     while( msg = (struct IntuiMessage *)GetMsg( win->UserPort ) )
  211.     ReplyMsg( (struct Message *) msg );
  212.     KbdBuffered = 0;
  213.     win->UserPort = (struct MsgPort *) 0;
  214.     ModifyIDCMP(win, 0L);
  215.     Permit();
  216.     CloseWindow(win);
  217. }
  218.  
  219. static int BufferGetchar()
  220. {
  221.     register int c;
  222.  
  223.     if (KbdBuffered > 0) {
  224.     c = KbdBuffer[0];
  225.     KbdBuffered--;
  226.     /* Move the remaining characters */
  227.     if( KbdBuffered < sizeof( KbdBuffer ) )
  228.         memcpy( KbdBuffer, KbdBuffer+1, KbdBuffered );
  229.     return c;
  230.     }
  231.  
  232.     return NO_CHAR;
  233. }
  234.  
  235. /*
  236.  *  This should remind you remotely of DeadKeyConvert, but we are cheating
  237.  *  a bit. We want complete control over the numeric keypad, and no dead
  238.  *  keys... (they are assumed to be on Alted keys).
  239.  *
  240.  *  Also assumed is that the IntuiMessage is of type RAWKEY.  For some
  241.  *  reason, IECODE_UP_PREFIX events seem to be lost when they  occur while
  242.  *  our console window is inactive. This is particulary  troublesome with
  243.  *  qualifier keys... Is this because I never RawKeyConvert those events???
  244.  */
  245.  
  246. int ConvertKey(message)
  247. register struct IntuiMessage *message;
  248. {
  249.     static struct InputEvent theEvent;
  250.     static char       numpad[] = "bjnh.lyku";
  251.     static char  ctrl_numpad[] = "\x02\x0A\x0E\x08.\x0C\x19\x0B\x15";
  252.     static char shift_numpad[] = "BJNH.LYKU";
  253.  
  254.     unsigned char buffer[1];
  255.     register int length;
  256.     register ULONG qualifier;
  257.     char numeric_pad, shift, control, alt;
  258.  
  259.     qualifier = message->Qualifier;
  260.  
  261.     control = (qualifier &  IEQUALIFIER_CONTROL) != 0;
  262.     shift   = (qualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT)) != 0;
  263.     alt     = (qualifier & (IEQUALIFIER_LALT   | IEQUALIFIER_RALT  )) != 0;
  264.  
  265.     /* Allow ALT to function as a META key ... */
  266.  
  267.     qualifier &= ~(IEQUALIFIER_LALT | IEQUALIFIER_RALT);
  268.     numeric_pad = (qualifier & IEQUALIFIER_NUMERICPAD) != 0;
  269.  
  270.     /*
  271.      *  Shortcut for HELP and arrow keys. I suppose this is allowed.
  272.      *  The defines are in intuition/intuition.h, and the keys don't
  273.      *  serve 'text' input, normally. Also, parsing their escape
  274.      *  sequences is such a mess...
  275.      */
  276.  
  277.     switch (message->Code) {
  278.     case RAWHELP:
  279.         if( alt )
  280.         {
  281.         EditColor();
  282.         return( -1 );
  283.         }
  284.         return( '?' );
  285.         break;
  286.     case CURSORLEFT:
  287.         length = '4';
  288.         numeric_pad = 1;
  289.         goto arrow;
  290.     case CURSORDOWN:
  291.         length = '2';
  292.         numeric_pad = 1;
  293.         goto arrow;
  294.     case CURSORUP:
  295.         length = '8';
  296.         numeric_pad = 1;
  297.         goto arrow;
  298.     case CURSORRIGHT:
  299.         length = '6';
  300.         numeric_pad = 1;
  301.         goto arrow;
  302.     }
  303.  
  304.     theEvent.ie_Class = IECLASS_RAWKEY;
  305.     theEvent.ie_Code = message->Code;
  306.     theEvent.ie_Qualifier = numeric_pad ? IEQUALIFIER_NUMERICPAD : qualifier;
  307.     theEvent.ie_EventAddress = (APTR) (message->IAddress);
  308.  
  309.     length = RawKeyConvert(&theEvent, (char *)buffer, 
  310.       (long) sizeof(buffer), NULL);
  311.  
  312.     if (length == 1) {   /* Plain ASCII character */
  313.     length = buffer[0];
  314.     /*
  315.      *  If flags.num_pad is set, movement is by 4286.
  316.      *  If not set, translate 4286 into hjkl.
  317.      *  This way, the numeric pad can /always/ be used
  318.      *  for moving, though best results are when it is off.
  319.      */
  320. arrow:
  321.     if (!flags.num_pad && numeric_pad && length >= '1' && length <= '9') {
  322.         length -= '1';
  323.         if (control) {
  324.         length = ctrl_numpad[length];
  325.         } else if (shift) {
  326.         length = shift_numpad[length];
  327.         } else {
  328.         length = numpad[length];
  329.         }
  330.     }
  331.     if (alt)
  332.         length |= 0x80;
  333.     return(length);
  334.     } /* else shift, ctrl, alt, amiga, F-key, shift-tab, etc */
  335.     else
  336.     return( -1 );
  337. }
  338.  
  339. /*
  340.  *  Process an incoming IntuiMessage.
  341.  *  It would certainly look nicer if this could be done using a
  342.  *  PA_SOFTINT message port, but we cannot call RawKeyConvert()
  343.  *  during a software interrupt.
  344.  *  Anyway, amikbhit()/kbhit() is called often enough, and usually gets
  345.  *  ahead of input demands, when the user types ahead.
  346.  */
  347.  
  348. static void ProcessMessage(message)
  349. register struct IntuiMessage *message;
  350. {
  351.     int c;
  352.     static int skip_mouse=0;    /* need to ignore next mouse event on
  353.                  * a window activation */
  354.     struct Window *w = message->IDCMPWindow;
  355.  
  356.     switch(message->Class) {
  357.     case ACTIVEWINDOW:
  358.     if( alwaysinvent && WIN_INVEN != WIN_ERR &&
  359.                 message->IDCMPWindow ==
  360.                 amii_wins[ WIN_INVEN ]->win )
  361.     {
  362.         DoMenuScroll( WIN_INVEN, 0 );
  363.     }
  364.     else if( scrollmsg && WIN_MESSAGE != WIN_ERR &&
  365.                 message->IDCMPWindow ==
  366.                 amii_wins[ WIN_MESSAGE ]->win )
  367.     {
  368.         DoMenuScroll( WIN_MESSAGE, 0 );
  369.     }
  370.     else
  371.     {
  372.         skip_mouse=1;
  373.     }
  374.     break;
  375.  
  376.     case MOUSEBUTTONS:
  377.     {
  378.         if( skip_mouse )
  379.         {
  380.         skip_mouse=0;
  381.         break;
  382.         }
  383.  
  384.         if( !amii_wins[ WIN_MAP ] || w != amii_wins[ WIN_MAP ]->win )
  385.         break;
  386.  
  387.         if( message->Code == SELECTUP )
  388.         {
  389. #ifdef    VIEWWINDOW
  390.         amii_putstr( WIN_MESSAGE, 0, "done..." );
  391.         w->Flags &= ~REPORTMOUSE;
  392. #endif
  393.         }
  394.         else if( message->Code == SELECTDOWN )
  395.         {
  396.         lastevent.type = WEMOUSE;
  397.         lastevent.un.mouse.x = message->MouseX;
  398.         lastevent.un.mouse.y = message->MouseY;
  399.             /* With shift equals RUN */
  400.         lastevent.un.mouse.qual = (message->Qualifier &
  401.           (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT)) != 0;
  402. #ifdef    VIEWWINDOW
  403.         w->Flags |= REPORTMOUSE;
  404.         amii_putstr( WIN_MESSAGE, 0,
  405.             "drag mouse to see other areas of this level" );
  406. #endif
  407.         }
  408.     }
  409.     break;
  410.  
  411.     case MENUPICK:
  412.     {
  413.         USHORT thismenu;
  414.         struct MenuItem *item;
  415.  
  416.         thismenu = message->Code;
  417.         while (thismenu != MENUNULL)
  418.         {
  419.         item = ItemAddress(HackMenu, (ULONG) thismenu);
  420.         if (KbdBuffered < KBDBUFFER)
  421.             BufferQueueChar(item->Command); /* Unused: No COMMSEQ */
  422.         thismenu = item->NextSelect;
  423.         }
  424.     }
  425.     break;
  426.  
  427.     case REFRESHWINDOW:
  428. #ifdef    VIEWWINDOW
  429.     {
  430.         struct Window *vw, *vbw;
  431.         if( amii_wins[ WIN_VIEWBOX ] && amii_wins[ WIN_VIEW ] &&
  432.             w == amii_wins[ WIN_VIEWBOX ]->win )
  433.         {
  434.         vw = amii_wins[ WIN_VIEW ]->win;
  435.         vbw = amii_wins[ WIN_VIEWBOX ]->win;
  436.  
  437.         if( vw->LeftEdge != (vbw->LeftEdge+vbw->BorderLeft) ||
  438.             vw->TopEdge != ( vbw->TopEdge + vbw->BorderTop ) ||
  439.             vw->Width != (vbw->Width -vbw->BorderLeft - vbw->BorderRight ) ||
  440.             vw->Height != (vbw->Height - vbw->BorderTop - vbw->BorderBottom ) )
  441.         {
  442.             MoveWindow( vw, (vbw->LeftEdge+vbw->BorderLeft) - vw->LeftEdge,
  443.             ( vbw->TopEdge + vbw->BorderTop ) - vw->TopEdge );
  444.             SizeWindow( vw,
  445.             ( vbw->Width -vbw->BorderLeft -
  446.                 vbw->BorderRight ) - vw->Width,
  447.             ( vbw->Height - vbw->BorderTop -
  448.                 vbw->BorderBottom - vw->Height ) );
  449.         }
  450.         }
  451.         else if( amii_wins[ WIN_MESSAGE ] && w == amii_wins[ WIN_MESSAGE ]->win )
  452.         {
  453.         DoMenuScroll( WIN_MESSAGE, 0 );
  454.         }
  455.     }
  456. #endif
  457.     break;
  458.  
  459.     case CLOSEWINDOW:
  460.     if( WIN_INVEN != WIN_ERR && message->IDCMPWindow ==
  461.                 amii_wins[ WIN_INVEN ]->win )
  462.     {
  463.         dismiss_nhwindow( WIN_INVEN );
  464.     }
  465.     break;
  466.  
  467.     case RAWKEY:
  468.     if (!(message->Code & IECODE_UP_PREFIX)){
  469.         /* May queue multiple characters
  470.          * but doesn't do that yet...
  471.          */
  472.         if( ( c = ConvertKey(message) ) > 0 )
  473.         BufferQueueChar( c );
  474.         }
  475.         break;
  476.  
  477.     case MOUSEMOVE:
  478. #ifdef    VIEWWINDOW
  479.     if( w == amii_wins[ WIN_MAP ]->win )
  480.     {
  481.         int posx, posy, dx, dy;
  482.         register struct MsgPort *port = w->UserPort;
  483.         struct amii_WinDesc *cw;
  484.  
  485.         posx = message->MouseX;
  486.         posy = message->MouseY;
  487.         cursor_on( WIN_MAP );
  488.         cw = amii_wins[ WIN_MAP ];
  489.  
  490.         do {
  491.         if( message->Class == MOUSEBUTTONS ||
  492.                     message->Class == INACTIVEWINDOW )
  493.         {
  494.             w->Flags &= ~REPORTMOUSE;
  495.             break;
  496.         }
  497.         else if( message->Class == MOUSEMOVE )
  498.         {
  499.             if( posx != message->MouseX || posy != message->MouseY )
  500.             {
  501.             dx = message->MouseX - posx;
  502.             dy = message->MouseY - posy;
  503.             dx /= MAPFTWIDTH;
  504.             dy /= MAPFTHEIGHT;
  505.             if( dx != 0 || dy != 0 )
  506.             {
  507.                 posx = message->MouseX;
  508.                 posy = message->MouseY;
  509.                 amii_curs( WIN_MAP,
  510.                 (posx - w->BorderLeft)/MAPFTWIDTH+dx,
  511.                 (posy - w->BorderTop)/MAPFTHEIGHT+dy );
  512.                 cursor_on( WIN_MAP );
  513.             }
  514.             }
  515.         }
  516.         ReplyMsg( (struct Message *) message );
  517.         while( !(message = (struct IntuiMessage *)GetMsg( port ) ) )
  518.             WaitPort( port );
  519.         } while( message );
  520.         amii_putstr( WIN_MESSAGE, 0, "done..." );
  521.         break;
  522.     }
  523. #endif
  524.     /* FALL through for MESSAGE or INVEN windows */
  525.     case GADGETDOWN:
  526.     if( WIN_MESSAGE != WIN_ERR && message->IDCMPWindow ==
  527.             amii_wins[ WIN_MESSAGE ]->win )
  528.     {
  529.         DoMenuScroll( WIN_MESSAGE, 0 );
  530.     }
  531.     else if( WIN_INVEN != WIN_ERR && message->IDCMPWindow ==
  532.             amii_wins[ WIN_INVEN ]->win )
  533.     {
  534.         DoMenuScroll( WIN_INVEN, 0 );
  535.     }
  536.     break;
  537.  
  538.     case NEWSIZE:
  539.     if( WIN_MESSAGE != WIN_ERR && message->IDCMPWindow ==
  540.             amii_wins[ WIN_MESSAGE ]->win )
  541.     {
  542.         ReDisplayData( WIN_MESSAGE );
  543.     }
  544.     else if( WIN_INVEN != WIN_ERR && message->IDCMPWindow ==
  545.             amii_wins[ WIN_INVEN ]->win )
  546.     {
  547.         ReDisplayData( WIN_INVEN );
  548.     }
  549.     break;
  550.     }
  551.     ReplyMsg((struct Message *) message);
  552. }
  553.  
  554. #endif /* AMII_GRAPHICS */
  555. /*
  556.  *  Get all incoming messages and fill up the keyboard buffer,
  557.  *  thus allowing Intuition to (maybe) free up the IntuiMessages.
  558.  *  Return when no more messages left, or keyboard buffer half full.
  559.  *  We need to do this since there is no one-to-one correspondence
  560.  *  between characters and incoming messages.
  561.  */
  562.  
  563. #if defined(TTY_GRAPHICS) && !defined(AMII_GRAPHICS)
  564. int kbhit(){return 0};
  565. #else
  566. int
  567. kbhit()
  568. {
  569.     int c;
  570. #ifdef TTY_GRAPHICS
  571.         /* a kludge to defuse the mess in allmain.c */
  572.         /* I hope this is the right approach */
  573.     if(windowprocs.win_init_nhwindows==amii_procs.win_init_nhwindows)return 0;
  574. #endif
  575.     c = amikbhit();
  576.     if( c <= 0 )
  577.         return( 0 );
  578.     return( c );
  579. }
  580. #endif
  581.  
  582. #ifdef AMII_GRAPHICS
  583.  
  584. int
  585. amikbhit()
  586. {
  587.     register struct IntuiMessage *message;
  588.     while( KbdBuffered < KBDBUFFER / 2 )
  589.     {
  590. #ifdef AMIFLUSH
  591.     message = (struct IntuiMessage *) GetFMsg(HackPort);
  592. #else
  593.     message = (struct IntuiMessage *) GetMsg(HackPort);
  594. #endif
  595.     if(message)
  596.     {
  597.         ProcessMessage(message);
  598.         if( lastevent.type != WEUNK && lastevent.type != WEKEY )
  599.         break;
  600.     }
  601.     else
  602.         break;
  603.     }
  604.     return ( lastevent.type == WEUNK ) ? KbdBuffered : -1;
  605. }
  606.  
  607. /*
  608.  *  Get a character from the keyboard buffer, waiting if not available.
  609.  *  Ignore other kinds of events that happen in the mean time.
  610.  */
  611.  
  612. int WindowGetchar( )
  613. {
  614.     while ((lastevent.type = WEUNK), amikbhit() <= 0) {
  615.     WaitPort(HackPort);
  616.     }
  617.     return BufferGetchar();
  618. }
  619.  
  620. WETYPE WindowGetevent()
  621. {
  622.     lastevent.type = WEUNK;
  623.     while (amikbhit() == 0)
  624.     {
  625.     WaitPort(HackPort);
  626.     }
  627.  
  628.     if( KbdBuffered )
  629.     {
  630.     lastevent.type = WEKEY;
  631.     lastevent.un.key = BufferGetchar();
  632.     }
  633.     return( lastevent.type );
  634. }
  635.  
  636. /*
  637.  *  Clean up everything. But before we do, ask the user to hit return
  638.  *  when there is something that s/he should read.
  639.  */
  640.  
  641. void amii_cleanup()
  642. {
  643.     register struct IntuiMessage *msg;
  644.  
  645.     /* Close things up */
  646.     if( HackPort )
  647.     {
  648.     amii_raw_print("");
  649.     amii_getret();
  650.     }
  651.  
  652.     if (ConsoleIO.io_Device)
  653.     CloseDevice( (struct IORequest *)&ConsoleIO );
  654.     ConsoleIO.io_Device = 0;
  655.  
  656.     if( ConsoleIO.io_Message.mn_ReplyPort )
  657.     DeletePort( ConsoleIO.io_Message.mn_ReplyPort );
  658.     ConsoleIO.io_Message.mn_ReplyPort = 0;
  659.  
  660.     /* Strip messages before deleting the port */
  661.     if( HackPort )
  662.     {
  663.     Forbid();
  664.     while (msg = (struct IntuiMessage *) GetMsg(HackPort))
  665.         ReplyMsg((struct Message *) msg);
  666.     kill_nhwindows( 1 );
  667.     DeletePort( HackPort );
  668.     HackPort = NULL;
  669.     Permit();
  670.     }
  671.  
  672.     /* Close the screen, under v37 or greater it is a pub screen and there may be
  673.      * visitors, so check close status and wait till everyone is gone.
  674.      */
  675.     if( HackScreen )
  676.     {
  677. #ifdef  INTUI_NEW_LOOK
  678.     if( IntuitionBase->LibNode.lib_Version >= 37 )
  679.     {
  680.         while( CloseScreen( HackScreen ) == FALSE )
  681.         {
  682.         struct EasyStruct easy =
  683.         {
  684.             sizeof( struct EasyStruct ),
  685.             0,
  686.             "Nethack Problem",
  687.             "Can't Close Screen, Close Visiting Windows",
  688.             "Okay",
  689.         };
  690.         EasyRequest( NULL, &easy, NULL, NULL );
  691.         }
  692.     }
  693.     else
  694. #endif
  695.     {
  696.         CloseScreen(HackScreen);
  697.     }
  698.     HackScreen = NULL;
  699.     }
  700.  
  701. #ifdef HACKFONT
  702.     if (HackFont)
  703.     {
  704.     CloseFont(HackFont);
  705.     HackFont = NULL;
  706.     }
  707.  
  708. #ifdef    VIEWWINDOW
  709.     if (HackFont4)
  710.     {
  711.     CloseFont(HackFont4);
  712.     HackFont4 = NULL;
  713.     }
  714.  
  715.     if (HackFont16)
  716.     {
  717.     CloseFont(HackFont16);
  718.     HackFont16 = NULL;
  719.     }
  720. #endif
  721.  
  722.     if( TextsFont )
  723.     {
  724.     CloseFont( TextsFont );
  725.     TextsFont = NULL;
  726.     }
  727.  
  728.     if( DiskfontBase )
  729.     {
  730.     CloseLibrary(DiskfontBase);
  731.     DiskfontBase = NULL;
  732.     }
  733. #endif
  734.  
  735. #ifdef    VIEWWINDOW
  736.     if (LayersBase) {
  737.     CloseLibrary((struct Library *)LayersBase);
  738.     LayersBase = NULL;
  739.     }
  740. #endif
  741.  
  742.     if (GfxBase) {
  743.     CloseLibrary((struct Library *)GfxBase);
  744.     GfxBase = NULL;
  745.     }
  746.  
  747.     if (IntuitionBase) {
  748.     CloseLibrary((struct Library *)IntuitionBase);
  749.     IntuitionBase = NULL;
  750.     }
  751.  
  752. #ifdef    SHAREDLIB
  753.     if (DOSBase) {
  754.     CloseLibrary((struct Library *)DOSBase);
  755.     DOSBase = NULL;
  756.     }
  757. #endif
  758.  
  759.     ((struct Process *) FindTask(NULL))->pr_WindowPtr = (APTR) pr_WindowPtr;
  760.  
  761.     Initialized = 0;
  762. }
  763.  
  764. #ifndef    SHAREDLIB
  765. void Abort(rc)
  766. long rc;
  767. {
  768.     int fault = 1;
  769. #ifdef CHDIR
  770.     extern char orgdir[];
  771.     chdir(orgdir);
  772. #endif
  773. #ifdef AMII_GRAPHICS
  774.     if (Initialized
  775.       && ConsoleDevice
  776.       && windowprocs.win_init_nhwindows==amii_procs.win_init_nhwindows) {
  777.       printf("\n\nAbort with alert code %08lx...\n", rc);
  778.       amii_getret();
  779.     } else
  780. #endif
  781.       printf("\n\nAbort with alert code %08lx...\n",rc);
  782. #if 0
  783.       Alert(rc);              /* this is too severe */
  784. #endif
  785. #ifdef __SASC
  786. #ifdef    INTUI_NEW_LOOK
  787.     {
  788.         struct EasyStruct es =
  789.         {
  790.             sizeof( struct EasyStruct ),
  791.             0,
  792.             "NetHack Panic Request",
  793.             "NetHack is Aborting with code == 0x%08lx",
  794.         "Continue Abort|Return to Program|Clean up and exit",
  795.         };
  796.         fault = EasyRequest( NULL, &es, NULL, (long)rc );
  797.         if( fault == 2 )
  798.             return;
  799.     }
  800. #endif
  801.     if( fault == 1 )
  802.     {
  803. /*  __emit(0x4afc);     /* illegal instruction */
  804.     __emit(0x40fc);     /* divide by */
  805.     __emit(0x0000);     /*  #0  */
  806.       /* NOTE: don't move amii_cleanup() above here - */
  807.       /* it is too likely to kill the system     */
  808.       /* before it can get the SnapShot out, if  */
  809.       /* there is something really wrong.    */
  810.     }
  811. #endif
  812. #ifdef AMII_GRAPHICS
  813.     if(windowprocs.win_init_nhwindows==amii_procs.win_init_nhwindows)
  814.       amii_cleanup();
  815. #endif
  816. #undef exit
  817. #ifdef AZTEC_C
  818.     _abort();
  819. #endif
  820.     exit((int) rc);
  821. }
  822.  
  823. void
  824. CleanUp()
  825. {
  826.     amii_cleanup();
  827. }
  828. #endif
  829.  
  830. #ifdef AMII_GRAPHICS
  831.  
  832. #ifdef AMIFLUSH
  833. /* This routine adapted from AmigaMail IV-37 by Michael Sinz */
  834. static struct Message *
  835. GetFMsg(port)
  836.     struct MsgPort *port;
  837.     {
  838.     struct IntuiMessage *msg,*succ,*succ1;
  839.  
  840.     if(msg=(struct IntuiMessage *)GetMsg(port)){
  841.     if(!flags.amiflush)return((struct Message *)msg);
  842.     if(msg->Class==RAWKEY){
  843.         Forbid();
  844.         succ=(struct IntuiMessage *)(port->mp_MsgList.lh_Head);
  845.         while(succ1=(struct IntuiMessage *)
  846.           (succ->ExecMessage.mn_Node.ln_Succ)){
  847.         if(succ->Class==RAWKEY){
  848.             Remove((struct Node *)succ);
  849.             ReplyMsg((struct Message *)succ);
  850.         }
  851.         succ=succ1;
  852.         }
  853.         Permit();
  854.     }
  855.     }
  856.     return((struct Message *)msg);
  857. }
  858. #endif
  859.  
  860. /*
  861.  * Begin Revamped Text display routines
  862.  *
  863.  * Up until version 3.1, the only method for displaying text on the playing
  864.  * field was by using the console.device.  This was nice for a number of
  865.  * reasons, the most signifigant of which was a lot of the nuts and bolts was
  866.  * done for you via escape sequences interpreted by said device.  This did
  867.  * not come without a price however.  And that price was speed. It has now
  868.  * come to a point where the speed has now been deemed unacceptable.
  869.  *
  870.  * The following series of routines are designed to drop into the current
  871.  * nethack display code, using hooks provided for such a measure. It works
  872.  * on similar principals as the WindowPuts(), buffering I/O internally
  873.  * until either an explicit flush or internal buffering is exceeded, thereby
  874.  * forcing the flush.  The output (or glyphs) does not go to the
  875.  * console.device, however.  It is driven directly to the rasterport of the
  876.  * nethack window via the low-level Text() calls, increasing the speed by
  877.  * a very signifigant factor.
  878.  */
  879. /*
  880.  * Routine to simply flush whatever is buffered
  881.  */
  882. void
  883. flush_glyph_buffer( w )
  884.     struct Window *w;
  885. {
  886.     short i, x, y;
  887. #ifdef    VIEWWINDOW
  888.     struct Window *vw = amii_wins[ WIN_VIEW ]->win;
  889.     register struct RastPort *vrp = vw->RPort;
  890. #endif
  891.     register struct RastPort *rp = w->RPort;
  892.  
  893.     /* If nothing is buffered, return before we do anything */
  894.     if(glyph_node_index == 0)
  895.     return;
  896.  
  897.     cursor_off( WIN_MAP );
  898.     start_glyphout( WIN_MAP );
  899. #ifdef    VIEWWINDOW
  900.     cursor_off( WIN_VIEW );
  901.     start_glyphout( WIN_VIEW );
  902. #endif
  903.  
  904.     /* Set up the drawing mode */
  905.     SetDrMd( rp, JAM2);
  906. #ifdef    VIEWWINDOW
  907.     SetDrMd( vrp, JAM2);
  908. #endif
  909.  
  910.     /* Go ahead and start dumping the stuff */
  911.     for(i=0; i<glyph_node_index; ++i) {
  912.     /* These coordinate calculations must be synced with the
  913.      * code in amii_curs() in winami.c.  curs_on_u() calls amii_curs()
  914.      * to draw the cursor on top of the player
  915.      */
  916.     y = w->BorderTop + (g_nodes[i].y-1) * rp->TxHeight +
  917.         rp->TxBaseline + 1;
  918.     x = g_nodes[i].x * rp->TxWidth + w->BorderLeft;
  919.  
  920.     /* Move pens to correct location */
  921.     Move( rp, (long)x, (long)y);
  922.  
  923.     /* Setup the colors */
  924.     SetAPen( rp, (long)g_nodes[i].fg_color);
  925.     SetBPen( rp, (long)g_nodes[i].bg_color);
  926.  
  927.     /* Do it */
  928.     Text( rp, g_nodes[i].buffer, g_nodes[i].len);
  929.  
  930. #ifdef    VIEWWINDOW
  931.     y = vw->BorderTop + (g_nodes[i].y-1) * vrp->TxHeight + vrp->TxBaseline + 1;
  932.     x = g_nodes[i].x * vrp->TxWidth + vw->BorderLeft;
  933.  
  934.     /* Move pens to correct location */
  935.     Move( vrp, (long)x, (long)y);
  936.  
  937.     /* Setup the colors */
  938.     SetAPen( vrp, (long)g_nodes[i].fg_color);
  939.     SetBPen( vrp, (long)g_nodes[i].bg_color);
  940.  
  941.     /* Do it */
  942.     Text( vrp, g_nodes[i].buffer, g_nodes[i].len);
  943. #endif
  944.     }
  945.  
  946.     amii_end_glyphout( WIN_MAP );
  947. #ifdef    VIEWWINDOW
  948.     amii_end_glyphout( WIN_VIEW );
  949. #endif
  950.     /* Clean up */
  951.     glyph_node_index = glyph_buffer_index = 0;
  952. }
  953.  
  954. /*
  955.  * Glyph buffering routine.  Called instead of WindowPuts().
  956.  */
  957. void
  958. amiga_print_glyph(window,color_index, glyph)
  959.     winid window;
  960.     int color_index, glyph;
  961. {
  962.     int fg_color, bg_color;
  963.     struct amii_WinDesc *cw;
  964.     struct Window *w;
  965.     int curx;
  966.     int cury;
  967.  
  968.     if( ( cw=amii_wins[window] ) == (struct amii_WinDesc *)NULL )
  969.     panic("bad winid in amiga_print_glyph: %d", window );
  970.  
  971.     w = cw->win;
  972.     curx=cw->curx;
  973.     cury=cw->cury;
  974.  
  975. #ifdef TEXTCOLOR
  976.     fg_color = foreg[color_index];
  977.     bg_color = backg[color_index];
  978. #else
  979.     fg_color = 1;
  980.     bg_color = 0;
  981. #endif /* TEXTCOLOR */
  982.  
  983.     /* See if we have enough character buffer space... */
  984.     if(glyph_buffer_index  >= GLYPH_BUFFER_SIZE)
  985.     flush_glyph_buffer( w );
  986.  
  987.     /*
  988.      * See if we can append it to the current active node of glyph buffer. It
  989.      * must satisfy the following conditions:
  990.      *
  991.      *    * background colors are the same, AND
  992.      *    * foreground colors are the same, AND
  993.      *    * they are precisely side by side
  994.      */
  995.     if((glyph_buffer_index != 0) &&
  996.        (fg_color == g_nodes[glyph_node_index-1].fg_color) &&
  997.        (bg_color == g_nodes[glyph_node_index-1].bg_color) &&
  998.        (g_nodes[glyph_node_index-1].x+
  999.     g_nodes[glyph_node_index-1].len == curx) &&
  1000.        (g_nodes[glyph_node_index-1].y == cury)) {
  1001.     /*
  1002.      * Add it to the end of the buffer
  1003.      */
  1004.     glyph_buffer[glyph_buffer_index++] = glyph;
  1005.     g_nodes[glyph_node_index-1].len ++;
  1006.      } else {
  1007.     /* See if we're out of glyph nodes */
  1008.     if(glyph_node_index >= NUMBER_GLYPH_NODES)
  1009.         flush_glyph_buffer( w );
  1010.     g_nodes[glyph_node_index].len = 1;
  1011.     g_nodes[glyph_node_index].x = curx;
  1012.     g_nodes[glyph_node_index].y = cury;
  1013.     g_nodes[glyph_node_index].fg_color = fg_color;
  1014.     g_nodes[glyph_node_index].bg_color = bg_color;
  1015.     g_nodes[glyph_node_index].buffer = &glyph_buffer[glyph_buffer_index];
  1016.     glyph_buffer[glyph_buffer_index] = glyph;
  1017.     ++glyph_buffer_index;
  1018.     ++glyph_node_index;
  1019.     }
  1020. }
  1021.  
  1022. /*
  1023.  * Define some variables which will be used to save context when toggling
  1024.  * back and forth between low level text and console I/O.
  1025.  */
  1026. static long xsave, ysave, modesave, apensave, bpensave;
  1027. static int usecolor;
  1028.  
  1029. /*
  1030.  * The function is called before any glyphs are driven to the screen.  It
  1031.  * removes the cursor, saves internal state of the window, then returns.
  1032.  */
  1033.  
  1034. void
  1035. start_glyphout(window)
  1036.     winid window;
  1037. {
  1038.     struct amii_WinDesc *cw;
  1039.     struct Window *w;
  1040.  
  1041.     if( ( cw=amii_wins[window] ) == (struct amii_WinDesc *)NULL )
  1042.     panic( "bad winid %d in start_glyphout()", window );
  1043.  
  1044.     if( cw->wflags & FLMAP_INGLYPH )
  1045.     return;
  1046.  
  1047.     if( !(w = cw->win ) )
  1048.     panic( "bad winid %d, no window ptr set", window );
  1049.  
  1050.     /*
  1051.      * Save the context of the window
  1052.      */
  1053.     xsave = w->RPort->cp_x;
  1054.     ysave = w->RPort->cp_y;
  1055.     modesave = w->RPort->DrawMode;
  1056.     apensave = w->RPort->FgPen;
  1057.     bpensave = w->RPort->BgPen;
  1058.  
  1059.     /*
  1060.      * Set the mode, and be done with it
  1061.      */
  1062.     usecolor = flags.use_color;
  1063.     flags.use_color = FALSE;
  1064.     cw->wflags |= FLMAP_INGLYPH;
  1065. }
  1066.  
  1067. /*
  1068.  * General cleanup routine -- flushes and restores cursor
  1069.  */
  1070. void
  1071. amii_end_glyphout(window)
  1072.     winid window;
  1073. {
  1074.     struct amii_WinDesc *cw;
  1075.     struct Window *w;
  1076.  
  1077.     if( ( cw = amii_wins[ window ] ) == (struct amii_WinDesc *)NULL )
  1078.     panic("bad window id %d in amii_end_glyphout()", window );
  1079.  
  1080.     if( ( cw->wflags & FLMAP_INGLYPH ) == 0 )
  1081.     return;
  1082.     cw->wflags &= ~(FLMAP_INGLYPH);
  1083.  
  1084.     if( !(w = cw->win ) )
  1085.     panic( "bad winid %d, no window ptr set", window );
  1086.  
  1087.     /*
  1088.      * Clean up whatever is left in the buffer
  1089.      */
  1090.     flags.use_color = usecolor;
  1091.  
  1092.     /*
  1093.      * Reset internal data structs
  1094.      */
  1095.     SetAPen(w->RPort, apensave);
  1096.     SetBPen(w->RPort, bpensave);
  1097.     SetDrMd(w->RPort, modesave);
  1098.  
  1099.     Move(w->RPort, xsave, ysave);
  1100. }
  1101.  
  1102. struct NewWindow *
  1103. DupNewWindow( win )
  1104.     struct NewWindow *win;
  1105. {
  1106.     struct NewWindow *nwin;
  1107.     struct Gadget *ngd, *gd, *pgd = NULL;
  1108.     struct PropInfo *pip;
  1109.     struct StringInfo *sip;
  1110.  
  1111.     /* Copy the (Ext)NewWindow structure */
  1112.  
  1113.     nwin = (struct NewWindow *)alloc( sizeof( struct NewWindow ) );
  1114.     *nwin = *win;
  1115.  
  1116.     /* Now do the gadget list */
  1117.  
  1118.     nwin->FirstGadget = NULL;
  1119.     for( gd = win->FirstGadget; gd; gd = gd->NextGadget )
  1120.     {
  1121.     ngd = (struct Gadget *)alloc( sizeof( struct Gadget ) );
  1122.     *ngd = *gd;
  1123.     if( gd->GadgetType == STRGADGET )
  1124.     {
  1125.         sip = (struct StringInfo *)alloc( sizeof( struct StringInfo ) );
  1126.         *sip = *((struct StringInfo *)gd->SpecialInfo);
  1127.         sip->Buffer = (UBYTE *) alloc( sip->MaxChars );
  1128.         *sip->Buffer = 0;
  1129.         ngd->SpecialInfo = (APTR)sip;
  1130.     }
  1131.     else if( gd->GadgetType == PROPGADGET )
  1132.     {
  1133.         pip = (struct PropInfo *)alloc( sizeof( struct PropInfo ) );
  1134.         *pip = *((struct PropInfo *)gd->SpecialInfo);
  1135.         ngd->SpecialInfo = (APTR)pip;
  1136.     }
  1137.     if( pgd )
  1138.         pgd->NextGadget = ngd;
  1139.     else
  1140.         nwin->FirstGadget = ngd;
  1141.     pgd = ngd;
  1142.     ngd->NextGadget = NULL;
  1143.     }
  1144.     return( nwin );
  1145. }
  1146.  
  1147. void
  1148. FreeNewWindow( win )
  1149.     struct NewWindow *win;
  1150. {
  1151.     register struct Gadget *gd, *pgd;
  1152.     register struct StringInfo *sip;
  1153.  
  1154.     for( gd = win->FirstGadget; gd; gd = pgd )
  1155.     {
  1156.     pgd = gd->NextGadget;
  1157.     if( gd->GadgetType == STRGADGET )
  1158.     {
  1159.         sip = (struct StringInfo *)gd->SpecialInfo;
  1160.         free( sip->Buffer );
  1161.         free( sip );
  1162.     }
  1163.     else if( gd->GadgetType == PROPGADGET )
  1164.  
  1165.     {
  1166.         free( (struct PropInfo *)gd->SpecialInfo );
  1167.     }
  1168.     free( gd );
  1169.     }
  1170.     free( win );
  1171. }
  1172.  
  1173. void
  1174. bell()
  1175. {
  1176.     if (flags.silent) return;
  1177.     DisplayBeep(NULL);
  1178. }
  1179.  
  1180. void
  1181. amii_delay_output()
  1182. {
  1183.     /* delay 50 ms */
  1184.     Delay(2L);
  1185. }
  1186.  
  1187. void
  1188. amii_number_pad(state)
  1189. int state;
  1190. {
  1191. }
  1192. #endif  /* AMII_GRAPHICS */
  1193.  
  1194. #ifndef    SHAREDLIB
  1195. void
  1196. amiv_loadlib( void )
  1197. {
  1198. }
  1199.  
  1200. void
  1201. amii_loadlib( void )
  1202. {
  1203. }
  1204.  
  1205. /* fatal error */
  1206. /*VARARGS1*/
  1207. void error VA_DECL(const char *, s)
  1208.     VA_START(s);
  1209.     VA_INIT(s, char *);
  1210.  
  1211.     putchar('\n');
  1212.     vprintf(s, VA_ARGS);
  1213.     putchar('\n');
  1214.  
  1215.     VA_END();
  1216.     Abort(0L);
  1217. }
  1218. #endif
  1219.